package controllers;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

import org.apache.commons.lang3.math.NumberUtils;

import models.Resource;
import models.Setting;
import play.data.Form;
import play.mvc.Controller;
import play.mvc.Result;
import services.ConfigurationService;
import services.ProjectService;
import services.SettingService;
import services.SynchronizationService;
import services.TestSuiteService;
import views.html.projects.*;

public class Projects extends Controller {
	
	private static final SettingService settingService = SettingService.getService();
	private static final SynchronizationService synchService = SynchronizationService.getService();
	private static final ConfigurationService configurationService = ConfigurationService.getService();
	private static final ProjectService projectService = ProjectService.getService();
	private static final TestSuiteService testSuiteService = TestSuiteService.getService();
	
	public static Result listProjects() {
		List<Resource> projects = projectService.getAllProjects();
		return ok(list.render(projects));
	}
	
	public static Result addProject() {
		Form<Resource> form = new Form<Resource>(Resource.class);
		return addProject(form);
	}
	
	private static Result addProject(Form<Resource> form) {
		List<Resource> projects = projectService.getAllProjects();
		List<Resource> configurations = configurationService.getAllConfigs();
		return ok(add.render(form, projects, configurations));
	}
	
	public static Result editProject(long projectId) {
		Resource project = projectService.getProject(projectId);
		if (project != null) {
			Form<Resource> form = Form.form(Resource.class).fill(project);
			return editProject(projectId, form);
		} else {
			return redirect(controllers.routes.Projects.listProjects());
		}
	}
	
	private static Result editProject(long projectId, Form<Resource> form) {
		Resource config = projectService.getDefaultConfig(projectId);
		long configId = 0;
		boolean configIsRemote;
		String configContent = null;
		if (config != null) {
			configId = config.getId();
			configIsRemote = config.isRemote();
			configContent = configurationService.getConfigFileContent(config);
		} else {
			configIsRemote = false;
			configContent = "";
		}
		form.data().put("default-configuration-id", Long.toString(configId));
		form.data().put("default-configuration-remote", Boolean.toString(configIsRemote));
		form.data().put("default-configuration", configContent);
		
		List<Resource> configurations = configurationService.getAllConfigs();
		List<Resource> testSuites = testSuiteService.getAllTestSuites(projectId);
		return ok(edit.render(projectId, form, configurations, testSuites));
	}
	
	public static Result createProject() {
		Form<Resource> form = Form.form(Resource.class).bindFromRequest();
		if (!form.hasErrors()) {
			Resource project = projectService.saveProject(form.get());
			
			boolean createConfig = true;
			long configId = 0;
			
			String defaultConfigId = Form.form().bindFromRequest().get("default-configuration-selection");
			if (NumberUtils.isNumber(defaultConfigId)) {
				configId = NumberUtils.toLong(defaultConfigId);
				if (configurationService.configExists(configId)) {
					createConfig = false;
				}
			}
			
			if (createConfig) {
				Resource defaultConfig = projectService.initialDefaultConfiguration(project);
				String configContent = Form.form().bindFromRequest().get("default-configuration");
				defaultConfig = configurationService.saveConfig(defaultConfig, configContent);
				configId = defaultConfig.getId();
			}
			
			projectService.setDefaultConfig(project.getId(), configId);
			
			return redirect(controllers.routes.Projects.listProjects());
		} else {
			return addProject(form);
		}
	}
	
	public static Result updateProject(long projectId) {
		Form<Resource> form = Form.form(Resource.class).bindFromRequest();
		if (!form.hasErrors()) {
			Resource project = projectService.getProject(projectId);
			Resource newProject = Form.form(Resource.class).bindFromRequest().get();
			project.setName(newProject.getName());
			project.setDescription(newProject.getDescription());
			project = projectService.saveProject(project);
			
			boolean createConfig = !project.isRemote();
			Resource currentDefaultConfig = projectService.getDefaultConfig(project.getId());
			String defaultConfigId = Form.form().bindFromRequest().get("default-configuration-selection");
			if (NumberUtils.isNumber(defaultConfigId)) {
				int configId = NumberUtils.toInt(defaultConfigId);
				if (configurationService.configExists(configId)) {
					if (!project.isRemote()) {
						String configContent = Form.form().bindFromRequest().get("default-configuration");
						currentDefaultConfig = configurationService.saveConfig(currentDefaultConfig, configContent);
					}
					if (currentDefaultConfig == null || currentDefaultConfig.getId() != configId) {
						projectService.replaceDefaultConfig(project.getId(), currentDefaultConfig != null ? currentDefaultConfig.getId() : 0, configId);
					}
					createConfig = false;
				}
			}
			
			if (createConfig) {
				Resource defaultConfig = projectService.initialDefaultConfiguration(project);
				String configContent = Form.form().bindFromRequest().get("default-configuration");
				defaultConfig = configurationService.saveConfig(defaultConfig, configContent);
				projectService.replaceDefaultConfig(project.getId(), currentDefaultConfig != null ? currentDefaultConfig.getId() : 0, defaultConfig.getId());
			}
			
			return redirect(controllers.routes.Projects.editProject(projectId));
		} else {
			return editProject(projectId, form);
		}
	}
	
	public static Result synchronizeProjects() {
		synchService.synchronizeProjects(settingService.getSetting(Setting.REMOTE_PROJECT_HOME).getStringValue());
		return redirect(controllers.routes.Projects.listProjects());
	}
	
	public static Result showDefaultConfig(long projectId) {
		Resource config = projectService.getDefaultConfig(projectId);
		if (config != null) {
			return redirect(controllers.routes.Configurations.editConfig(config.getId()));
		} else {
			return redirect(controllers.routes.Projects.listProjects());
		}
	}
	
	public static Result runTestsWithDefaultConfig(long projectId) {
		Resource defaultConfig = projectService.getDefaultConfig(projectId);
		return runTestsWithConfig(projectId, defaultConfig);
	}
	
	public static Result runTestsWithConfig(long projectId, long configId) {
		Resource config = configurationService.getConfig(configId);
		return runTestsWithConfig(projectId, config);
	}
	
	private static Result runTestsWithConfig(long projectId, Resource config) {
		Resource project = projectService.getProject(projectId);
		if (project == null || config == null) {
			return redirect(controllers.routes.Projects.listProjects());
		}
		String content = "";
		try {
			URL url = new URL(settingService.getSetting(Setting.TEST_EXECUTION_URL).getStringValue() + "/cgi-bin/console/execute.py?projectid=" + project.getName() + "&suite=all&variablefile=" + config.getName());
			
			URLConnection connection = url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
			String line;
			while ((line = in.readLine()) != null) {
				content += line + "\n";
			}
			in.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ok(content);
	}
}
